#include "Contig.h"


Contig::Contig(void)
{
	m_id = 0;
	m_name = "";
	m_length = 0;
	m_copyNum = 0;
	m_occu = 0;
	m_isInScaffold = false;
	m_isVec = false;

	leftEdge = new map< int, pair<Contig*, int> >;
	rightEdge = new map< int, pair<Contig*, int> >;
	m_gaps = new list<Gap*>;

	inEdges = new list<int>;
	outEdges = new list<int>;
	inEdgesNew = new list<int>;
	outEdgesNew = new list<int>;

	m_combinedNodes = new list<pair<string, string> >;
}

Contig::Contig( int id, int length )
{
	m_id = id;
	m_name = "NODE_" + itos( id );
	m_length = length;
	leftEdge = new map< int, pair<Contig*, int> >;
	rightEdge = new map< int, pair<Contig*, int> >;
	m_occu = 0;
	m_isInScaffold = false;
	m_gaps = new list<Gap*>;
	m_isVec = false;

	inEdges = new list<int>;
	outEdges = new list<int>;
	inEdgesNew = new list<int>;
	outEdgesNew = new list<int>;
	m_combinedNodes = new list<pair<string, string> >;
	m_combinedNodes->push_back( pair<string, string>("+", m_name) );
}

Contig::~Contig(void)
{
	delete leftEdge;
	delete rightEdge;

	inEdges->clear();
	delete inEdges;
	outEdges->clear();
	delete outEdges;
	inEdgesNew->clear();
	delete inEdgesNew;
	outEdgesNew->clear();
	delete outEdgesNew;
}

void Contig::SetCov( double cov )
{
	m_cov = cov;
}

string Contig::GetName()
{
	return m_name;
}

double Contig::GetCov()
{
	return m_cov;
}

// add right edge
void Contig::AddRightEdge( int contigID, Contig *contig, int size )
{
	AddEdge( contigID, contig, size, rightEdge );
}

// add left edge
void Contig::AddLeftEdge( int contigID, Contig *contig, int size )
{
	AddEdge( contigID, contig, size, leftEdge );
}

// get id
int Contig::GetID()
{
	return m_id;
}

// contigID will contain orientation information: +/-
void Contig::AddEdge( int contigID, Contig *contig, int size, map<int, pair<Contig*, int> > *edges )
{
	pair<Contig*, int> newPair( contig, size );
	edges->insert( pair< int, pair<Contig*, int> >(contigID, newPair ) );
}

// check if this contig has multiple neighbors
bool Contig::HasMultipleNeighbors()
{
	if( leftEdge->size() > 1 || rightEdge->size() > 1 )
		return true;
	else
		return false;
}

int Contig::GetLength() 
{
	return m_length;
}

int Contig::GetNumberOfNeighbors()
{
	int num = leftEdge->size();
	num += rightEdge->size();
	return num;
}

map<int, pair<Contig*, int> >* Contig::GetEdge( int type )
{
	if( type == LEFT )
		return leftEdge;
	else
		return rightEdge;
}

void Contig::SetCopyNum( int c )
{
	m_copyNum = c;
	if( c == 0 )
		m_copyNum = 1;
}

int Contig::GetCopyNum()
{
	return m_copyNum;
}

// add one accurrence
void Contig::AddOccu()
{
	m_occu++;
}

int Contig::GetOccu()
{
	return m_occu;
}

void Contig::RemoveOccu()
{
	m_occu--;
}

void Contig::SetName( string s )
{
	m_name = s;
	m_combinedNodes->clear();
	m_combinedNodes->push_back( pair<string, string>("+", m_name)  );
}

void Contig::SetInScaffold()
{
	m_isInScaffold = true;
}

bool Contig::IfInScaffold()
{
	return m_isInScaffold;
}

// add a gap which contains this contig
void Contig::AddGap( Gap *g )
{
	m_gaps->push_back( g );
}

list<Gap*>* Contig::GetRelatedGaps()
{
	return m_gaps;
}

void Contig::SetVector( int start, int end, int ori )
{
	m_startPos = start;
	m_endPos = end; 
	m_vecOri = ori;
}

void Contig::SetIfPrintInVec( bool p )
{
	m_ifPrintInVec = p;
}

bool Contig::IfPrintInVec()
{
	return m_ifPrintInVec;
}

void Contig::SetStepInVecGraph( int s )
{
	m_stepInVecGraph = s;
}
	
int Contig::GetStepInVecGraph()
{
	return m_stepInVecGraph;
}

void Contig::SetIfVec( bool v )
{
	m_isVec = v;
}
	
bool Contig::IfVec()
{
	return m_isVec;
}

int Contig::GetVecOri()
{
	return m_vecOri;
}

int Contig::GetStartInVec()
{
	return m_startPos;
}
	
int Contig::GetEndInVec()
{
	return m_endPos;
}

void Contig::AddNewInEdgeVar( int x )
{
	inEdgesNew->push_back( x );
}

void Contig::AddNewOutEdgeVar( int x )
{
	outEdgesNew->push_back( x );
}

list<int>* Contig::GetNewInEdgeVar()
{
	return inEdgesNew;
}

list<int>* Contig::GetNewOutEdgeVar()
{
	return outEdgesNew;
}

// add new variables to all variables
void Contig::CombineVariables()
{
	inEdges->insert( inEdges->end(), inEdgesNew->begin(), inEdgesNew->end() );
	inEdgesNew->clear();
	outEdges->insert( outEdges->end(), outEdgesNew->begin(), outEdgesNew->end() );
	outEdgesNew->clear();
}

list<int>* Contig::GetInEdgeVar()
{
	return inEdges;
}

list<int>* Contig::GetOutEdgeVar()
{
	return outEdges;
}

void Contig::ClearVar()
{
	inEdges->clear();
	outEdges->clear();
}

// remove this node from all related gaps
void Contig::RemoveFromAllGaps()
{
	for( list<Gap*>::iterator gapIter = m_gaps->begin(); gapIter != m_gaps->end(); gapIter++ )
	{
		// remove from this gap
		(*gapIter)->RemoveNode( this );
	}

	m_gaps->clear();
}

void Contig::SetLength( int l )
{
	m_length = l;
}

void Contig::AddCombinedNode( Contig *c, int direction, int ori )
{
	list<pair<string, string> > *addedNames = c->GetCombinedNodes();

	if( direction == RIGHT )
	{ // add to the end of names
		if( ori == PLUS )
		{ // add the original names
			this->m_combinedNodes->insert( m_combinedNodes->end(), addedNames->begin(), addedNames->end() );
		}
		else
		{ // reverse the names
			for( list<pair<string, string> >::reverse_iterator nameIter = addedNames->rbegin(); nameIter != addedNames->rend(); nameIter++ )
			{
				if( (*nameIter).first == "+" )
					this->m_combinedNodes->push_back( pair<string, string>("-", (*nameIter).second) );
				else
					this->m_combinedNodes->push_back( pair<string, string>("+", (*nameIter).second) );
			}
		}
	}
	else
	{ // add to the start of the names
		if( ori == PLUS )
		{ // add the original names
			this->m_combinedNodes->insert( m_combinedNodes->begin(), addedNames->begin(), addedNames->end() );
		}
		else
		{ // reverse the names
			for( list<pair<string, string> >::iterator nameIter = addedNames->begin(); nameIter != addedNames->end(); nameIter++ )
			{
				if( (*nameIter).first == "+" )
					this->m_combinedNodes->push_front( pair<string, string>("-", (*nameIter).second) );
				else
					this->m_combinedNodes->push_front( pair<string, string>("+", (*nameIter).second) );
			}
		}
	}
}

list<pair<string, string> >* Contig::GetCombinedNodes()
{
	return m_combinedNodes;
}

void Contig::SetPlusSeq( string s )
{
	m_plusSeq = s;
}
	
void Contig::SetMinusSeq( string s )
{
	m_minusSeq = s;
}
	
string Contig::GetPlusSeq()
{
	return m_plusSeq;
}
	
string Contig::GetMinusSeq()
{
	return m_minusSeq;
}

// check if this contig is in scaffold and extend right
bool Contig::CheckIfExtendRight( set<Gap*> *gaps )
{
	for( set<Gap*>::iterator gapIter = gaps->begin(); gapIter != gaps->end(); gapIter++ )
	{
		if( ( (*gapIter)->GetStartContig() == this && (*gapIter)->GetStartOri() == PLUS ) 
				|| ( (*gapIter)->GetEndContig() == this && (*gapIter)->GetEndOri() == MINUS ) )
				return true;
	}
	return false;
}

// check if this contig is in scaffold and extend left
bool Contig::CheckIfExtendLeft( set<Gap*> *gaps )
{
	for( set<Gap*>::iterator gapIter = gaps->begin(); gapIter != gaps->end(); gapIter++ )
	{
		if( ( (*gapIter)->GetStartContig() == this && (*gapIter)->GetStartOri() == MINUS ) 
				|| ( (*gapIter)->GetEndContig() == this && (*gapIter)->GetEndOri() == PLUS ) )
				return true;
	}
	return false;
}
